<template>
  <div class="main-content-box">
    <div class="demoDiv">
      <div class="title_for_layout">
        <h3>确定X、Y坐标值</h3>
      </div>
      <div class="toolDiv">
        <div class="zoom zoomOut" title="放大" @click="getZoomOut">
          <i class="iconfont">&#xe640;</i>
        </div>
        <div class="zoom zoomIn" title="缩小" @click="getZoomIn">
          <i class="iconfont">&#xe624;</i>
        </div>
        <div class="zoom lineFlow" title="路线" @click="showLineFlow">
          <i class="iconfont">&#xe641;</i>
        </div>
      </div>
      <div id="container"></div>
      <div class="showDetails" v-if="isShowDetails">
        <p class="details-title">详细信息</p>
        <span class="closeDetail" @click="closeDetail">
          <i class="iconfont">&#xe60b;</i>
        </span>
        <div class="details-info">
          <div class="details-info-items">
            <h4 class="info-items-label">名称：</h4>
            <h4 class="info-items">{{showNodeDetailsObj.label}}</h4>
          </div>
          <div class="details-info-items">
            <h4 class="info-items-label">Id：</h4>
            <h4 class="info-items">{{showNodeDetailsObj.id}}</h4>
          </div>
          <div class="details-info-items">
            <h4 class="info-items-label">状态：</h4>
            <h4 class="info-items"></h4>
          </div>
          <div class="details-info-items">
            <h4 class="info-items-label">描述信息：</h4>
            <p class="info-items-description">此处是对节点的一些介绍描述信息</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import G6 from '@antv/g6';
import Util from "@antv/g6/lib/util";
export default {
  name: 'g6demo9',
  data () {
    return {
      currentGraph: {},
      lineEdge: [],
      lineEdgeArrOne: [],
      lineEdgeArrTwo: [],
      clickNum: 0,
      isShowDetails: false,
      showNodeDetailsObj: {},
      showEdgeDetailsObj: {}
    }
  },
  mounted () {
    this.initGrahp()
  },
  methods: {
    initGrahp () {
      let _that = this  //保存vue实例，避免data中的值重新赋值以后不能改变的问题
      const nodes = [];
      const edges = [];

      // 主节点
      const centerNode = {
        id: 'center',
        x: 10,
        y: 280,
        size: 36,
        label: 'WIN -STARTNODE \n 10.0.1.2',
        text: '\ue600',  //对应iconfont.css 里面的content，注意加u
        style: {
          fill: 'red'
        },
        labelCfg: {
          style: {
            fill: "blue"
          }
        },
        backgroundConfig: null,  // 自定义项，用于判读是否需要圆背景
        anchorPoints: [
          [1, 0.5]
        ]
      };
      nodes.push(centerNode);
      //r2节点
      let R2Node = {
        id: 'R2Node',
        x: 100,
        y: 290,
        size: 36,
        label: 'R2 \n 10.0.1.1',
        text: '\ue679',  //对应iconfont.css 里面的content，注意加u
        style: {
          fill: 'Coral'
        },
        labelCfg: {
          style: {
            fill: "blue"
          }
        },
        backgroundConfig: null,  // 自定义项，用于判读是否需要圆背景
        anchorPoints: [
          [0, 0.5],
          [1, 0.5],
          [0.5, 0],
          [0.5, 1]
        ]
      }
      nodes.push(R2Node);
      edges.push({
        id: 'edgestart-R2',
        source: 'center',
        target: 'R2Node',
        type: 'can-running',
        label: '9ms ',
        sourceAnchor: 0,
        targetAnchor: 0,
      });
      //r1节点
      let R1Node = {
        id: 'R1Node',
        x: 650,
        y: 450,
        size: 36,
        label: 'R1 \n 10.0.2.50',
        text: '\ue679',  //对应iconfont.css 里面的content，注意加u
        style: {
          fill: 'Coral'
        },
        labelCfg: {
          style: {
            fill: "blue"
          }
        },
        backgroundConfig: null,  // 自定义项，用于判读是否需要圆背景
        anchorPoints: [
          [0, 0.5],
          [1, 0.5]
        ]
      }
      nodes.push(R1Node);
      edges.push({
        id: 'edgeR2-R1',
        source: 'R2Node',
        target: 'R1Node',
        type: 'can-running',
        label: '9ms',
        sourceAnchor: 3,
        targetAnchor: 0,
      });
      edges.push({
        id: 'edgeR1-R9',
        source: 'R1Node',
        target: 'R9Node',
        type: 'can-running',
        label: '19ms',
        sourceAnchor: 1,
        targetAnchor: 2,
        curveOffset: [10, 20, 50, 100, 50, 10, 0],
      });
      //r3节点
      let R3Node = {
        id: 'R3Node',
        x: 280,
        y: 120,
        size: 36,
        label: 'R3 \n 10.0.2.6',
        text: '\ue679',  //对应iconfont.css 里面的content，注意加u
        style: {
          fill: 'Coral'
        },
        labelCfg: {
          style: {
            fill: "blue"
          }
        },
        backgroundConfig: null,
        anchorPoints: [
          [0, 0.5],
          [1, 0.5]
        ]
      }
      nodes.push(R3Node);
      edges.push({
        id: 'edgeR2-R3',
        source: 'R2Node',
        target: 'R3Node',
        type: 'can-running',
        label: '19ms',
        sourceAnchor: 2,
        targetAnchor: 0,
      });
      edges.push({
        id: 'edgeR3-R8',
        source: 'R3Node',
        target: 'R8Node',
        type: 'can-running',
        label: '11ms',
        sourceAnchor: 1,
        targetAnchor: 1,
      });

      //r5节点
      let R5Node = {
        id: 'R5Node',
        x: 270,
        y: 220,
        size: 36,
        label: 'R5 \n 10.0.2.10',
        text: '\ue679',
        style: {
          fill: 'Coral'
        },
        labelCfg: {
          style: {
            fill: "blue"
          }
        },
        backgroundConfig: null,
        anchorPoints: [
          [0, 0.5],
          [1, 0.5]
        ]
      }
      nodes.push(R5Node);
      edges.push({
        id: 'edgeR2-R5',
        source: 'R2Node',
        target: 'R5Node',
        type: 'can-running',
        label: '18ms',
        sourceAnchor: 1,
        targetAnchor: 0,
      });

      //r8节点
      let R8Node = {
        id: 'R8Node',
        x: 400,
        y: 250,
        size: 36,
        label: 'R8 \n 10.0.2.34',
        text: '\ue679',
        style: {
          fill: 'Coral'
        },
        labelCfg: {
          style: {
            fill: "blue"
          }
        },
        backgroundConfig: null,
        anchorPoints: [
          /*  [0, 0], //lefttop
           [1, 0], // righttop
           [0,1], // leftbottom
           [1, 1], // rightbottom
            */
          [0, 0.5], //left
          [0.5, 0], // top
          [1, 0.5], // right
          [0.5, 1], // bottom
          [1, 0]
        ]
      }
      nodes.push(R8Node);
      edges.push({
        id: 'edgeR5-R8',
        source: 'R5Node',
        target: 'R8Node',
        type: 'can-running',
        label: '17ms',
        sourceAnchor: 1,
        targetAnchor: 0,
      });

      //r9节点
      let R9Node = {
        id: 'R9Node',
        x: 550,
        y: 280,
        size: 36,
        label: 'R9 \n 10.0.2.82',
        text: '\ue679',
        style: {
          fill: 'red'
        },
        labelCfg: {
          style: {
            fill: "red"
          }
        },
        backgroundConfig: null,
        anchorPoints: [
          [0, 0.5], //left
          [0.5, 0], // top
          [1, 0.5], // right
          [0.5, 1] // bottom
        ]
      }
      nodes.push(R9Node);
      // edges.push({
      //   source: 'R8Node',
      //   target: 'R9Node',
      //   type: 'can-running',
      //   label: '4ms',
      //   sourceAnchor: 2,
      //   targetAnchor: 0,
      // });
      edges.push({
        id: 'edgeR8-R9-1',
        source: 'R8Node',
        target: 'R9Node',
        type: 'can-running',
        label: '4ms',
        sourceAnchor: 2,
        targetAnchor: 1,
        curveOffset: [50, 100],
      });
      edges.push({
        id: 'edgeR8-R9-2',
        source: 'R8Node',
        target: 'R9Node',
        type: 'can-running',
        label: '14ms',
        sourceAnchor: 3,
        targetAnchor: 3,
        curveOffset: -50,
        // curvePosition: [0, 0.2, 0.5, 0.7, 0.8, 0.5, 1]
      });


      //END节点
      let endNode = {
        id: 'endNode',
        x: 680,
        y: 80,
        size: 36,
        label: 'Net sulte',
        text: '\ue743',
        style: {
          fill: 'Coral'
        },
        labelCfg: {
          style: {
            fill: "red"
          }
        },
        backgroundConfig: null  // 自定义项，用于判读是否需要圆背景
      }
      nodes.push(endNode);
      edges.push({
        id: 'edgeR9-end',
        source: 'R9Node',
        target: 'endNode',
        type: 'can-running',
        label: '5ms',
        color: 'cyan',
        size: 5,
        style: {
          lineDash: [4, 4]
        }
      });

      //使用iconfont
      G6.registerNode('iconfont', {
        draw (cfg, group) {
          const { backgroundConfig: backgroundStyle, style, labelCfg: labelStyle } = cfg;

          if (backgroundStyle) {
            group.addShape('circle', {
              attrs: {
                x: 0,
                y: 0,
                r: cfg.size,
                ...backgroundStyle,
              },
              name: 'circle-shape',
            });
          }
          group.addShape('circle', {
            attrs: {
              x: -12,
              y: 0,
              r: 30,
              ...backgroundStyle,
            },
            name: 'circle-shape',
          });

          const keyShape = group.addShape('text', {
            attrs: {
              x: 0,
              y: 0,
              fontFamily: 'iconfont', // 对应css里面的font-family: "iconfont";
              textAlign: 'center',
              textBaseline: 'bottom',
              text: cfg.text,
              fontSize: cfg.size,
              ...style,
            },
            name: 'text-shape1',
          });
          const labelY = backgroundStyle ? cfg.size * 2 : cfg.size;

          group.addShape('text', {
            attrs: {
              x: 0,
              y: labelY,
              textAlign: 'center',
              text: cfg.label,
              ...labelStyle.style,
            },
            name: 'text-shape1',
          });
          return keyShape;
        },
      });
      /**
       * 定义要一个变量，存储点击右键时的节点属性值
       */
      let temObj = {}

      const dashArray = [
        [0, 1],
        [0, 2],
        [1, 2],
        [0, 1, 1, 2],
        [0, 2, 1, 2],
        [1, 2, 1, 2],
        [2, 2, 1, 2],
        [3, 2, 1, 2],
        [4, 2, 1, 2],
      ];
      const lineDash = [4, 2, 1, 2];
      const interval = 9;

      G6.registerEdge(
        'can-running',
        {
          setState (name, value, item) {
            const shape = item.get('keyShape');
            if (name === 'running') {
              if (value) {
                const length = shape.getTotalLength(); // 后续 G 增加 totalLength 的接口
                let totalArray = [];
                for (let i = 0; i < length; i += interval) {
                  totalArray = totalArray.concat(lineDash);
                }
                let index = 0;
                shape.animate(
                  () => {
                    const cfg = {
                      lineDash: dashArray[index].concat(totalArray),
                      // lineWidth: 3   //线条宽度

                      // lineWidth: 20,
                      lineAppendWidth: 50,
                    };
                    index = (index + 1) % interval;
                    return cfg;
                  },
                  {
                    repeat: true,
                    duration: 3000,
                  },
                );
                // shape.attr('lineDash');
              } else {
                shape.stopAnimate();
                shape.attr('lineDash', null);
              }
            }
          },
        },
        'cubic-horizontal', // 其他内置边效果不如此类型美观
      );

      G6.registerEdge(
        'line-dash',
        {
          afterDraw (cfg, group) {
            // 获得该边的第一个图形，这里是边的 path
            const shape = group.get('children')[0];
            // 获得边的 path 的总长度
            const length = shape.getTotalLength();
            let totalArray = [];
            // 计算出整条线的 lineDash
            for (let i = 0; i < length; i += interval) {
              totalArray = totalArray.concat(lineDash);
            }

            let index = 0;
            // 边 path 图形的动画
            shape.animate(
              () => {
                // 每一帧的操作，入参 ratio：这一帧的比例值（Number）。返回值：这一帧需要变化的参数集（Object）。
                const cfg = {
                  lineDash: dashArray[index].concat(totalArray),
                };
                // 每次移动 1
                index = (index + 1) % interval;
                // 返回需要修改的参数集，这里只修改了 lineDash
                return cfg;
              },
              {
                repeat: true, // 动画重复
                duration: 3000, // 一次动画的时长为 3000
              },
            );
          }
        },
        'cubic',
      );
      /**
       * 添加右键点击菜单
       */
      // JSX and HTML templates are available for the menu
      // create ul
      const conextMenuContainer = document.createElement('ul');
      conextMenuContainer.id = 'contextMenu';

      // create li
      const firstLi = document.createElement('li');
      firstLi.innerHTML = `查看节点`;
      firstLi.addEventListener('click', function (ev) {
        console.log(ev)
        console.log('点击了第一个li')
        console.log(this)
        _that.isShowDetails = true
        _that.showNodeDetailsObj = temObj
      })
      conextMenuContainer.appendChild(firstLi);

      /* document.getElementById('contextMenu').innerHTML =
        `<li @click="showDetails">Option 1</li>` */

      /* const lastLi = document.createElement('li');
      lastLi.innerText = 'Option 2';
      conextMenuContainer.appendChild(lastLi); */
      document.getElementById('container').appendChild(conextMenuContainer);


      let COLOR = '#40a9ff'
      const width = document.getElementById('container').scrollWidth;
      const height = document.getElementById('container').scrollHeight || 700;
      const graph = new G6.Graph({
        container: 'container',
        width,
        height,
        renderer: 'svg', // 此属性解决初始化时icon显示为方框的问题，但存在边错位现象
        // fitView: true,
        // linkCenter: true, //此属性会使边显示时穿过节点
        modes: {
          default: [
            'drag-canvas',
            'drag-node',
            // 'collapse-expand',  //此属性会报错，提示findDataById 不是函数,此属性只适用于树图
            'zoom-canvas'
          ]
        },
        defaultNode: {
          backgroundConfig: {
            backgroundType: 'circle',
            fill: COLOR,
            stroke: 'LightSkyBlue',
          },
          type: 'iconfont',
          size: 12,
          style: {
            fill: '#DEE9FF',
            stroke: '#5B8FF9',
          },
          labelCfg: {
            // autoRotate: true,
            style: {
              fill: COLOR,
              fontSize: 12,
            },
            position: 'center',
            offset: 500
          }
        },
        defaultEdge: {
          type: 'can-running',
          style: {
            stroke: '#b5b5b5',
          },
          lineAppendWidth: 50,
        },
        layout: {
          // type: 'circular', //布局的类型
          // center: [100, 100], //图的中心
          // radius: null,
          // preventOverlap: true,
        }
      });
      graph.data({ nodes, edges });
      graph.render();
      graph.fitView()
      setTimeout(() => {
        graph.paint();
      }, 16)

      // 响应 hover 状态
      graph.on('node:mouseenter', ev => {
        const node = ev.item;
        const edges = node.getEdges();
        // console.log(ev)
        // console.log(node)
        // console.log(edges)
        edges.forEach(edge => graph.setItemState(edge, 'running', true));
      });
      graph.on('node:mouseleave', ev => {
        const node = ev.item;
        const edges = node.getEdges();
        let model = {
          type: 'can-running',
          color: 'cyan',
          size: 5,
          style: {
            lineDash: [4, 4]
          }
        }
        edges.forEach(edge => {
          graph.setItemState(edge, 'running', false)
          if (edge._cfg.id === 'edgeR9-end') {
            graph.updateItem(edge, model)
          }
        });
      });
      graph.on('edge:click', ev => {
        console.log(ev)
        console.log('点击了一条边')
        _that.isShowDetails = true
        _that.showNodeDetailsObj = ev.item._cfg.model
      })
      /**
       * 存在问题，鼠标单击后 图形、节点跟随移动
       */
      _that.currentGraph = graph
      /**
       * 添加右键事件
       */

      graph.on('node:contextmenu', evt => {
        evt.preventDefault();
        evt.stopPropagation();
        console.log(evt)

        conextMenuContainer.style.left = `${evt.canvasX + 36}px`; //使菜单出现在节点的右侧
        conextMenuContainer.style.top = `${evt.canvasY}px`;

        temObj = evt.item._cfg.model
        // _that.showNodeDetailsObj = evt.item._cfg.model
      });

      graph.on('node:mouseleave', () => {
        conextMenuContainer.style.left = '-300px';
        // _that.isShowDetails = false
      });


      /**
       * 获取所有的边，根据边确定连线
       */
      graph.findAll('edge', edge => {
        // console.log(edge)

        // let sstyle = edge.getCurrentStatesStyle()
        // let sstyle = edge.getOriginStyle()
        // console.log(sstyle)
      })
      let alledge = graph.getEdges()
      // console.log(alledge)
      // console.log(typeof alledge)
      _that.lineEdge = alledge // 全部边
      let item1 = graph.findById('edgestart-R2');
      let item2 = graph.findById('edgeR2-R1');
      let item3 = graph.findById('edgeR1-R9');
      let item4 = graph.findById('edgeR2-R3');
      let item5 = graph.findById('edgeR3-R8');
      let item6 = graph.findById('edgeR2-R5');
      let item7 = graph.findById('edgeR5-R8');
      let item8 = graph.findById('edgeR8-R9-1');
      let item9 = graph.findById('edgeR8-R9-2');
      let item10 = graph.findById('edgeR9-end');
      //确定line数组  第一个
      _that.lineEdgeArrOne.push(item1, item2, item3, item10)

      //确定line数组  第二个
      _that.lineEdgeArrTwo.push(item1, item4, item5, item8, item10)

      /**
       * 点击画布 隐藏详细信息
       */
      graph.on('canvas:click', () => {
        _that.isShowDetails = false
      })
    },
    getZoomOut () {
      console.log('点击了放大')
      console.log(this.currentGraph)
      let currentZoom = this.currentGraph.getZoom();
      this.currentGraph.zoomTo(currentZoom + 0.1, this.getViewCenter());
    },
    getZoomIn () {
      console.log('点击了缩小')
      const currentZoom = this.currentGraph.getZoom();
      this.currentGraph.zoomTo(currentZoom - 0.1, this.getViewCenter());

    },


    /**
     * 线条动画、线路
     */
    showLineFlow () {
      // console.log('点击了线路')
      // console.log(this.lineEdge)
      // console.log(this.lineEdgeArrOne)
      // console.log(this.lineEdgeArrTwo)
      // console.log(this.clickNum)
      let model = {
        type: 'can-running',
        color: 'cyan',
        size: 5,
        style: {
          lineDash: [4, 4]
        }
      }
      let orgModel = {
        type: 'can-running',
        style: {
          lineWidth: 3
        }
      }

      switch (this.clickNum >= 0) {
        case this.clickNum % 4 === 0:
          //所以线设置动效
          this.lineEdge.forEach(item => {
            // this.currentGraph.updateItem(item, orgModel)
            this.currentGraph.setItemState(item, 'running', true)
          })
          break;
        case this.clickNum % 4 === 1:
          console.log('线1')
          //所以线取消动效
          this.lineEdge.forEach(item => {
            this.currentGraph.setItemState(item, 'running', false)
          })
          //lineEdgeArrOne设置动效
          this.lineEdgeArrOne.forEach(item => {
            this.currentGraph.setItemState(item, 'running', true)
          })
          break;
        case this.clickNum % 4 === 2:
          console.log('线2')
          this.lineEdge.forEach(item => {
            this.currentGraph.setItemState(item, 'running', false)
          })
          this.lineEdgeArrTwo.forEach(item => {
            this.currentGraph.setItemState(item, 'running', true)
          })
          break;
        case this.clickNum % 4 === 3:
          console.log('全部取消')
          this.lineEdge.forEach(item => {
            this.currentGraph.setItemState(item, 'running', false)
            if (item._cfg.id === 'edgeR9-end') {
              this.currentGraph.updateItem(item, model)
            }
          })
          break;
      }
      this.clickNum++
      /* this.lineEdge.forEach(item => {
        console.log(item)
        console.log(item._cfg.id)
        this.currentGraph.setItemState(item, 'running', true)
      }) */
    },

    /**
     * 计算画布的padding值
     */
    getFormatPadding () {
      console.log(this.currentGraph.get("fitViewPadding"))
      // console.log(Util)
      // console.log(Util.formatPadding)
      return Util.formatPadding(this.currentGraph.get("fitViewPadding"));
    },
    /**
     * 画布中心位置
     */
    getViewCenter () {
      const padding = this.getFormatPadding();
      const graph = this.currentGraph;
      const width = this.currentGraph.get("width");
      const height = graph.get("height");
      return {
        x: (width - padding[2] - padding[3]) / 2 + padding[3],
        y: (height - padding[0] - padding[2]) / 2 + padding[0]
      };
    },
    closeDetail () {
      this.isShowDetails = false
      this.showNodeDetailsObj = {}
    }
  }
}
</script>

<style scoped>
.main-content-box {
  width: 95%;
  margin: 5px 20px;
}
.demoDiv {
  position: relative;
  padding: 20px;
  border: 1px solid skyblue;
}
.toolDiv {
  width: 50px;
  border: 1px solid #f5f5f5;
  position: absolute;
}
/* #container {
  border: 1px solid rgb(145, 167, 175);
} */
.zoom {
  cursor: pointer;
  border: 1px solid #f5f5f5;
  font-size: 26px;
  background-color: #ffffff;
}
/* 右键菜单及显示详情区域 */
.showDetails {
  width: 12vw;
  height: 40vh;
  border: 1px solid #f5f5f5;
  box-shadow: -5px 5px 5px #aaaaaa;
  position: absolute;
  top: 0;
  right: 0;
  border-radius: 4px;
  background-color: #ffffff;
  padding: 5px;
  overflow-y: auto;
  font-size: 12px;
}
.details-title {
  text-align: left;
}
.closeDetail {
  position: absolute;
  right: 8px;
  top: 18px;
  cursor: pointer;
}
.closeDetail:hover {
  color: #e27e7e;
}
.details-info {
  margin: 0 10px;
  background-color: aquamarine;
}
.details-info-items {
  background-color: #ffffff;
  display: flex;
}
.details-info-items:last-child {
  background-color: #ffffff;
  display: flex;
  flex-direction: column;
  align-items: baseline;
}
.info-items {
  font-size: 12px;
  color: #545454;
  text-align: left;
}
.info-items-label {
  color: #000000;
  text-align: left;
  width: 65px;
}
.info-items-description {
  height: 100px;
  width: 100%;
  border: 1px solid #d2bebe;
  margin-top: 0px;
  line-height: 24px;
}
/* 右键菜单 */
.demoDiv >>> #contextMenu {
  position: absolute;
  list-style-type: none;
  padding: 10px 8px;
  left: -300px;
  background-color: rgba(255, 255, 255, 0.9);
  border: 1px solid #e2e2e2;
  border-radius: 4px;
  font-size: 14px;
  color: #545454;
}
.demoDiv >>> #contextMenu li {
  cursor: pointer;
  list-style-type: none;
  list-style: none;
  margin-left: 0px;
}
.demoDiv >>> #contextMenu li:hover {
  color: #aaa;
}
.title_for_layout {
  position: absolute;
  top: 0;
  left: 100px;
  color: crimson;
}
</style>